﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp.Demos.SimplePipeline
{
    public class ApplicationBuilderByCustom : IApplicationBuilderByCustom
    {

        private readonly IList<Func<RequestDelegateByCustom, RequestDelegateByCustom>> _middlewares =
            new List<Func<RequestDelegateByCustom, RequestDelegateByCustom>>();

        public RequestDelegateByCustom Build()
        {
            // 兜底的处理器
            // 返回 404 Code
            RequestDelegateByCustom next = context =>
            {
                context.Response.StatusCode = 404;
                return Task.CompletedTask;
            };

            // 注意，这里使用 Reverse 方法
            // 如果注册的时候是 A->B->C
            // 此处执行的就是 C->B->A 
            // C 先 Invoke 兜底的 next_404，返回值再给 B 进行 Invoke，最后 B Invoke 的返回值，给 A 进行 Invoke
            // A Invoke 的返回值，就是最终调用链的入口
            // 所以说，最终还是会先执行 A 的逻辑

            // A 的入参 next 是 B 的返回值
            // B 的入参 next 是 C 的返回值
            // C 的入参 next 是 next_404（兜底返回值）

            // 外部系统触发时
            // 传递一个 HttpContextByCustom，开头的 RequestDelegate 开始执行
            // 执行完成后，然后决定是否调用下一个 next（参数还是使用开头那个 HttpContextByCustom） 

            foreach (var middleware in _middlewares.Reverse())
            {
                next = middleware.Invoke(next);
            }

            // 最终得到的这个 next 就是 A 委托执行后的返回值（A/B/C 都会 Invoke 执行）

            // A 的返回值 <RequestDelegateByCustom> 也是一个委托，委托实现就是具体的业务执行逻辑 
            // 在这个逻辑里面，会判断是否执行下一个 next

            // 示例：async context => ...  代码块就是 A 的返回值
            // 里面执行了具体逻辑后，判断是否要调用 next

            /*
             *         public static RequestDelegateByCustom FooMiddleware(RequestDelegateByCustom next)
                            => async context =>
                             {
                                 await context.Response.WriteAsyncByCustom("Foo=>");
                                 await next(context);
                             };
            */

            // 由于 RequestDelegateByCustom 只是一个方法，所以需要一个执行触发的点
            // 当传递一个 HttpContextByCustom 时，就触发了这个调用流程
            // 所以，就需要一个扩展点，来执行这个调用

            // 这个扩展点，在 WebHostedServiceByCustom 中触发

            return next;
        }

        public IApplicationBuilderByCustom UseByCustom(Func<RequestDelegateByCustom, RequestDelegateByCustom> middleware)
        {
            _middlewares.Add(middleware);
            return this;
        }
    }
}
